package networkLoader;

import java.text.Format;
import java.util.ArrayList;
import java.util.Formatter;

import common.Rule;

public class FattreeNetwork {

    private static VNetwork buildTopology(int k) {
        VNetwork n = new VNetwork();
        //// create devices
        for (int iPod = 0; iPod < k; iPod++) {
            for (int j = 0; j < k / 2; j++) {
                VDevice device = n.addDevice("rsw-" + iPod + "-" + j);
                // add rsw -> host port
                device.addPort(String.format("rsw-%d-%d>h-%d-%d", iPod, j, iPod, j));
            }

            for (int j = 0; j < k / 2; j++) {
                n.addDevice("fsw-" + iPod + "-" + j);
            }
        }
        for (int iSsw = 0; iSsw < k * k / 4; iSsw++) {
            n.addDevice("ssw-" + iSsw);
        }
        //// \create devices

        //// create links
        for (int iPod = 0; iPod < k; iPod++) {
            for (int iFsw = 0; iFsw < k / 2; iFsw++) {
                String fsw = "fsw-" + iPod + "-" + iFsw;
                // down links
                for (int iRsw = 0; iRsw < k / 2; iRsw++) {
                    String rsw = "rsw-" + iPod + "-" + iRsw;
                    n.addLink(fsw, fsw + ">" + rsw, rsw, rsw + ">" + fsw);
                }
                // up links
                for (int iSsw = iFsw * k / 2; iSsw < iFsw * k / 2 + k / 2; iSsw++) {
                    String ssw = "ssw-" + iSsw;
                    n.addLink(fsw, fsw + ">" + ssw, ssw, ssw + ">" + fsw);
                }
            }
        }
        //// \create links
        return n;
    }

    public static VNetwork getNetwork(int npod) {
        VNetwork n = buildTopology(npod);

        //// create rules
        // first 8 bits is pod id, next 8 bit is index of rsw in pod
        for (int iPod = 0; iPod < npod; iPod++) {
            for (int iRsw = 0; iRsw < npod/2; iRsw++) {
                String rsw = "rsw-" + iPod + "-" + iRsw;
                VDevice device = n.getDevice(rsw);
                for (int jPod = 0; jPod < npod; jPod++) {
                    for (int jRsw = 0; jRsw < npod/2; jRsw++) {
                        String dstrsw = "rsw-" + jPod + "-" + jRsw;
                        long dstip = (jPod << 24) + ((jRsw + 1) << 16);
                        Rule rule;
                        if (dstrsw.equals(rsw)) {
                            rule = new Rule(dstip, 16, rsw + ">h-" + jPod + "-" + jRsw);
                        } else {
                            String dstfsw = "fsw-" + iPod + "-" + (npod/2 * jPod + jRsw) % (npod/2);
                            rule = new Rule(dstip, 16, rsw + ">" + dstfsw);
                        }
                        device.addInitialRule(rule);
                    }
                }
            }
            for (int iFsw = 0; iFsw < npod/2; iFsw++) {
                String fsw = "fsw-" + iPod + "-" + iFsw;
                VDevice device = n.getDevice(fsw);
                for (int jPod = 0; jPod < npod; jPod++) {
                    for (int jRsw = 0; jRsw < npod/2; jRsw++) {
                        String dstrsw = "rsw-" + jPod + "-" + jRsw;
                        long dstip = (jPod << 24) + ((jRsw + 1) << 16);
                        Rule rule;
                        if (jPod == iPod) { // intra pod
                            rule = new Rule(dstip, 16, fsw + ">" + dstrsw);
                        } else {
                            String dstssw = "ssw-" + (iFsw * (npod/2) + ((npod/2) * jPod + jRsw) % (npod/2));
                            rule = new Rule(dstip, 16, fsw + ">" + dstssw);
                        }
                        device.addInitialRule(rule);
                    }
                }
            }
        }

            for (int iSsw = 0; iSsw < npod*npod/4; iSsw++) {
                String ssw = "ssw-" + iSsw;
                VDevice device = n.getDevice(ssw);
                for (int k = 0; k < npod; k++) {
                    for (int l = 0; l < npod/2; l++) {
                        long dstip = (k << 24) + ((l + 1) << 16);
                        String dstfsw = "fsw-" + k + "-" + (iSsw / (npod/2));
                        Rule rule = new Rule(dstip, 16, ssw + ">" + dstfsw);
                        device.addInitialRule(rule);
                    }
                }
        }
        //// \create rules

        return n;
    }

    public static void main(String[] args) {
        VNetwork net = getNetwork(48); // create the virtual network with 112 pods

        // iterate the network to query the devices, links and rules
        for (VDevice vDevice : net.getDevices()) {
            System.out.println(vDevice.getName());
            
            // query links
            for (VPort vPort : vDevice.getPorts()) {
                VPort peer = vPort.getPeer();
                if (peer != null) { // peer == null means the vPort is an external port
                    // note: each pair of peers will iterate twice, be careful for redundency if you treat the peers as a single link object
                    System.out.println(String.format("link from %s:%s -> %s:%s", vDevice.getName(), vPort.getName(), peer.getVDevice().getName(), peer.getName()));
                }
            }

            // query initial rules
            ArrayList<Rule> rules = vDevice.getInitialRules();
            // do your routine with the rules
            
        }
    }
}
